package cn.anecansaitin.whimsy.common.attachment;

import net.minecraft.nbt.CompoundTag;
import net.neoforged.neoforge.common.util.INBTSerializable;

public class DoomfistSkill implements INBTSerializable<CompoundTag> {
    public RocketPunch rocketPunch = new RocketPunch();
    public SeismicSlam seismicSlam = new SeismicSlam();
    public PowerBlock powerBlock = new PowerBlock();
    public MeteorStrike meteorStrike = new MeteorStrike();
    public UltimateEfficiency ultimateEfficiency = new UltimateEfficiency();

    public void tick() {
        int cd = 1;
        //火箭重拳
        rocketPunch.tick(cd);
        //裂地重拳
        seismicSlam.tick(cd);
        //悍将格挡
        powerBlock.tick(cd);
        //毁天灭地
        meteorStrike.tick(cd);
        //最佳防守
        ultimateEfficiency.tick();
    }

    @Override
    public CompoundTag serializeNBT() {
        CompoundTag tag = new CompoundTag();
        //火箭重拳
        tag.put("punch", rocketPunch.serializeNBT());
        //裂地重拳
        tag.put("seismic_slam", seismicSlam.serializeNBT());
        //悍将格挡
        tag.put("power_block", powerBlock.serializeNBT());
        //毁天灭地
        tag.put("meteor_strike", meteorStrike.serializeNBT());
        //最佳防守
        tag.put("ultimate_efficiency", ultimateEfficiency.serializeNBT());
        return tag;
    }

    @Override
    public void deserializeNBT(CompoundTag nbt) {
        //火箭重拳
        rocketPunch.deserializeNBT(nbt.getCompound("punch"));
        //裂地重拳
        seismicSlam.deserializeNBT(nbt.getCompound("seismic_slam"));
        //悍将格挡
        powerBlock.deserializeNBT(nbt.getCompound("power_block"));
        //毁天灭地
        meteorStrike.deserializeNBT(nbt.getCompound("meteor_strike"));
        //最佳防守
        ultimateEfficiency.deserializeNBT(nbt.getCompound("ultimate_efficiency"));
    }

    public static class RocketPunch implements INBTSerializable<CompoundTag> {
        /**
         * 默认总CD
         */
        public final int defaultTick = 4 * 20;
        /**
         * 默认最大蓄力时间
         */
        public final int maxRechargeTick = 20;
        /**
         * 默认最大右击时间
         */
        public final int maxChargingTick = 32;
        /**
         * 冷却CD
         */
        public int cd;
        /**
         * 蓄力时间
         */
        public int rechargeTick;
        /**
         * 右击总时间
         */
        public int chargingTick;
        /**
         * 是否为强化拳
         */
        public boolean isEnhanced;
        /**
         * 是否正在蓄力
         */
        public boolean isCharging;
        /**
         * 技能是否正在释放中
         */
        public boolean isCasting;

        private RocketPunch() {}

        private void tick(int cd) {
            if (isCharging) {
                if (rechargeTick < maxRechargeTick) {
                    rechargeTick++;
                }

                if (chargingTick < maxChargingTick) {
                    chargingTick++;
                }
            } else if (!isCasting && this.cd > 0) {
                this.cd -= cd;
            }
        }

        public boolean tryUse() {
            if (cd <= 0 && !isCharging && !isCasting) {
                cd = defaultTick;
                rechargeTick = 0;
                isCharging = true;
                isCasting = true;
                return true;
            } else {
                return false;
            }
        }

        public void chargeComplete() {
            chargingTick = 0;
            isCharging = false;
            isEnhanced = false;
        }

        public void castingComplete() {
            rechargeTick = 0;
            isCasting = false;
        }

        public void interrupt() {
            isCharging = false;
            isCasting = false;
            rechargeTick = 0;
            chargingTick = 0;
        }

        public void resetting() {
            cd = 0;
            rechargeTick = 0;
            chargingTick = 0;
            isEnhanced = false;
            isCharging = false;
            isCasting = false;
        }

        public void setEnhanced() {
            isEnhanced = true;
        }

        public boolean isChargingComplete() {
            return chargingTick >= maxChargingTick;
        }

        public boolean isInCharging() {
            return chargingTick > 0 && chargingTick < maxChargingTick;
        }

        @Override
        public CompoundTag serializeNBT() {
            CompoundTag tag = new CompoundTag();
            tag.putInt("cd", cd);
            tag.putInt("recharge_tick", rechargeTick);
            tag.putInt("charging_tick", chargingTick);
            tag.putBoolean("is_enhanced", isEnhanced);
            tag.putBoolean("is_charging", isCharging);
            tag.putBoolean("is_casting", isCasting);
            return tag;
        }

        @Override
        public void deserializeNBT(CompoundTag nbt) {
            cd = nbt.getInt("cd");
            rechargeTick = nbt.getInt("recharge_tick");
            chargingTick = nbt.getInt("charging_tick");
            isEnhanced = nbt.getBoolean("is_enhanced");
            isCharging = nbt.getBoolean("is_charging");
            isCasting = nbt.getBoolean("is_casting");
        }
    }
    public static class SeismicSlam implements INBTSerializable<CompoundTag> {
        public int defaultCd = 6 * 20;
        public int cd;
        public boolean isCasting;

        private SeismicSlam() {}

        public void tick(int cd) {
            if (this.cd > 0 && !isCasting) {
                this.cd -= cd;
            }
        }

        public boolean tryUse() {
            if (cd <= 0 && !isCasting) {
                cd = defaultCd;
                isCasting = true;
                return true;
            } else {
                return false;
            }
        }

        public void castingComplete() {
            isCasting = false;
        }

        @Override
        public CompoundTag serializeNBT() {
            CompoundTag tag = new CompoundTag();
            tag.putInt("cd", cd);
            tag.putBoolean("is_casting", isCasting);
            return tag;
        }

        @Override
        public void deserializeNBT(CompoundTag nbt) {
            cd = nbt.getInt("cd");
            isCasting = nbt.getBoolean("is_casting");
        }
    }
    public static class PowerBlock implements INBTSerializable<CompoundTag> {
        public final int maxDamage = 10;
        public final int defaultCd = 7 * 20;
        public int cd;
        public boolean isCasting;
        public float blockedDamage;

        private PowerBlock() {}

        public void tick(int cd) {
            if (this.cd > 0 && !isCasting) {
                this.cd -= cd;
            }
        }

        public boolean tryUse() {
            if (cd <= 0 && !isCasting) {
                cd = defaultCd;
                isCasting = true;
                return true;
            } else {
                return false;
            }
        }

        public void castingComplete() {
            isCasting = false;
            blockedDamage = 0;
        }

        /**
         * @return 本次吸收能量是否达到充能阈值
         */
        public boolean addDamage(float damage) {
            if (isCasting && blockedDamage < maxDamage) {
                blockedDamage = Math.min(maxDamage, damage + blockedDamage);

                return blockedDamage >= maxDamage;
            }

            return isCasting && blockedDamage >= maxDamage;
        }

        @Override
        public CompoundTag serializeNBT() {
            CompoundTag tag = new CompoundTag();
            tag.putInt("cd", cd);
            tag.putBoolean("is_casting", isCasting);
            tag.putFloat("blocked_damage", blockedDamage);
            return tag;
        }

        @Override
        public void deserializeNBT(CompoundTag nbt) {
            cd = nbt.getInt("cd");
            isCasting = nbt.getBoolean("is_casting");
            blockedDamage = nbt.getFloat("blocked_damage");
        }
    }
    public static class MeteorStrike implements INBTSerializable<CompoundTag> {
        private final int defaultCdDelay = 20 / 5;
        private int cdDelay;
        public int defaultCd = 1950;
        public int cd = defaultCd;
        public boolean isCasting;

        private MeteorStrike() {}

        public void tick(int cd) {
            if (cd > 0 && !isCasting) {
                if (cdDelay == 0) {
                    this.cd -= cd;
                    cdDelay = defaultCdDelay;
                } else {
                    cdDelay--;
                }
            }
        }

        public boolean tryUse() {
            if (cd <= 0 && !isCasting) {
                cd = defaultCd;
                isCasting = true;
                return true;
            } else {
                return false;
            }
        }

        public void charge(int damage) {
            cd = Math.max(0, cd - damage);
        }

        @Override
        public CompoundTag serializeNBT() {
            CompoundTag tag = new CompoundTag();
            tag.putInt("cd_delay", cdDelay);
            tag.putInt("cd", cd);
            tag.putBoolean("is_casting", isCasting);
            return tag;
        }

        @Override
        public void deserializeNBT(CompoundTag nbt) {
            cdDelay = nbt.getInt("cd_delay");
            cd = nbt.getInt("cd");
            isCasting = nbt.getBoolean("is_casting");
        }
    }
    public static class UltimateEfficiency implements INBTSerializable<CompoundTag> {
        public double max = 20;
        /**
         * 衰减延迟，当获取护盾后，延迟一定时间才开始衰减
         */
        public int defaultAttenuationDelay = 20;
        /**
         * 衰减速率，每一tick衰减的护盾量
         */
        public float attenuationRate = 0.015f;
        public int attenuationDelay;

        private UltimateEfficiency() {}

        public void tick() {
            if (attenuationDelay > 0) {
                attenuationDelay--;
            }
        }

        public void generate() {
            attenuationDelay = defaultAttenuationDelay;
        }

        public boolean shouldAttenuate() {
            return attenuationDelay <= 0;
        }

        @Override
        public CompoundTag serializeNBT() {
            CompoundTag tag = new CompoundTag();
            tag.putInt("attenuation_delay", attenuationDelay);
            return tag;
        }

        @Override
        public void deserializeNBT(CompoundTag nbt) {
            attenuationDelay = nbt.getInt("attenuation_delay");
        }
    }
}
